Хостинг → Выбор сервера приложений для rails
У веб-разработчиков часто возникает вопрос: какой же метод запуска rails приложений выбрать? Попробуем рассмотреть плюсы и минусы каждого из них. Сразу оговоримся, что вариант jruby (запуск ruby кода в jvm) оставим без внимания, как специфический и для нашего проекта не очень интересный.
Mongrel
Первый метод, что приходит в голову, — Mongrel cluster. В основном, именно он описан в литературе по ruby on rails, он же используется для запуска rails-кода в режиме разработки (development environment). Все, что необходимо для запуска rails с mongrel cluster уже разработано и идет в стандартной поставке, также готовы и методы для capistrano. Казалось бы: бери, да пользуйся! Но, как говорится, без ложки дегтя тут не обходится.
Как же работает rails-приложение, запущенное при помощи mongrel cluster? Слово cluster в данном случае использовано не случайно. Дело в том, что сервер mongrel умеет обрабатывать одновременно только один запрос, поэтому запускается некоторое количество серверов на разных портах. Чтобы скрыть эти нюансы от посетителей сайта, используется прокси-сервер. Он распределяет между серверами mongrel запросы для своевременной их обработки. Каждый mongrel — это процесс, который выполняется независимо от своих «собратьев». Поскольку все они работают с одной базой данных и одной версией кода, запросы могут приходить на любой из них. Никаких проблем это не вызывает. Если ваш сервер перестал справляться с нагрузкой, вы легко можете добавить к нему еще один, запустив на нем еще некоторое количество серверов mongrel. Изменений в коде приложения для такой кластеризации делать не придется, ведь ruby on rails изначально рассчитан на данный подход. Единственное, придется обеспечить всем серверам доступ к хранилищу сессионных данных. Это могут быть и СУБД, и memcached, и примонтированная сетевая файловая система (NFS). Такое действие необходимо для того, чтобы при случайном распределении запросов по серверам сессия пользователя не терялась, т.к. первый его запрос может обрабатывать один mongrel, второй — уже другой и т.д.
А вот теперь пора поговорить о минусах. Самый очевидный из них заключается в том, что каждый из серверов mongrel в силу своей автономности будет загружать в память собственную копию кода rails, кода приложения и всех необходимых библиотек. Вот вам и обратная сторона простого кода сервера и легкой возможности кластеризации. При среднем проекте каждый mongrel запросто потребляет около 100М памяти. И если запускать на сайт по три сервера mongrel (т.к. одного явно недостаточно), то память будет потребляться в очень больших количествах. Да, сегодня 300-500 мегабайт памяти – цифра не слишком серьезная. Однако не стоит забывать, что речь идет о разделяемом хостинге, а значит число таких сайтов будет измеряться сотнями. В такой ситуации потребление памяти действительно становится проблемой.
Thin
Еще одной слабой стороной сервера приложений mongrel является то, что он обязательно занимает один порт. Это создает возможность для различных коллизий и трудно отслеживаемых ошибок. Например, пользователю A выделены порты 3001, 3002 и 3003. Он остановил на время свой mongrel-кластер, а пользователь B в это время взял и запустил на 3001-м порту собственный. При старте один из серверов mongrel пользователя A обязательно упадет, так как порт, который он собирается прослушивать, уже занят другим процессом. Пользователь A ничего не сможет с этим сделать, ведь он никак не может остановить процесс пользователя B. А тем временем один из трех запросов на сайт пользователя A будет попадать на чужой mongrel, так как фронтенд настроен именно на эти порты. Конечно, обратившись к администрации сервера, пользователь A решит свои проблемы, но осадочек останется… Есть ли выход? Дать определенному пользователю возможность прослушивать только конкретный список портов средствами современных операционных систем не так-то просто, все это лишь еще раз усложнит общую систему. Хорошим решением было бы слушать не порт, а unix сокет, но mongrel не обладает такой возможностью.Еще один известный метод запуска rails приложений – thin. Он разработан с использованием EventMachine и Rack, достаточно хорошо оптимизирован. Это делает его более производительным сервером, чем mongrel. Thin обладает теми же что и mongrel особенностями в вопросах одновременной обработки запросов и кластеризации. В сравнении с mongrel он потребляет меньше памяти, но по-прежнему загружает всю копию rails для каждого экземпляра. Большим и важным для хостеров плюсом thin является то, что он умеет «слушать» unix-сокеты вместо стандартных tcp портов. Это позволяет избежать неприятной проблемы, что была описана в примере для сервера mongrel. Ограничивать права на сокет, по сути являющийся файлом с атрибутами чтения и записи, гораздо проще и удобнее. К тому же работа через unix-сокеты ведется быстрее из-за отсутствия накладных расходов на tcp/ip стэк. Мы по возможности рекомендуем использовать unix-сокеты вместо tcp портов. Это действительно положительно сказывается на скорости работы приложения. В качестве подтверждения — ссылка на некоторые результаты сравнения серверов thin и mongrel с точки зрения производительности.
Настройка и запуск thin не сложнее чем у сервера mongrel, конфигурационный файл по-прежнему представляет из себя YML. Для capistrano так же легко добавить нужный код в deploy.rb, чтобы перезапуск серверов thin происходил автоматически при выкладывании новой версии кода. С thin вместо mongrel хостеру (а значит и пользователям) живется действительно легче. Однако проблема большого потребления памяти все еще остается. Ведь получается, что для каждого проекта независимо от текущего количества запросов будет запущено несколько серверов thin, а каждый из них поместит в память весь код rails и самого приложения.
Passenger
Попробуем решить проблему с памятью при помощи Phusion Passenger, известного также как mod_rails или mod_rack. Passenger — это модуль для популярных сегодня веб-серверов Apache и Nginx. Он изначально создан для запуска большого количества rails приложений. Passenger грамотно распределяет ресурсы и потребляет память по мере необходимости. Проблем с прослушиванием большого количества портов разными процессами тоже, по понятным причинам, нет. При этом в конфигурационном файле можно указать интерпретатор ruby, который будет использоваться для запуска rails. Это при желании позволит использовать ruby enterprise edition и выиграть в потреблении памяти еще до 30%. Для пользователя все опять же остается достаточно прозрачно. Для перезагрузки кода приложения теперь нужно просто создать файл tmp/restart.txt или изменить его время последнего доступа. Это легко автоматизируется средствами capistrano. Каждый проект до сих пор имеет возможность использовать свою версию rails, достаточно лишь установить необходимый gem. Passenger устанавливается при помощи rubygems, затем вам нужно будет скомпилировать модуль для вашего веб-сервера и включить его в сборку. По умолчанию код rails будет запускаться с правами пользователя, который владеет файлом environment.rb. Это поведение вполне удобно для хостера, но при желании его можно изменить соответствующими настройками, описанными в документации. Возможность кластеризации при этом остается, просто уже не диктуется необходимостью: ведь никто не мешает поставить несколько веб-серверов, на которых работает passenger за балансирующим прокси.
Phusion Passenger умеет работать не только с rails, но и с любым приложением, которое следует rack-интерфейсу. Это позволяет запускать код, разработанный с использованием фреймворков Merb, Sinatra и других rack-приложений. Мы выбрали для себя связку Nginx + Passenger как самую выгодную по производительности и удобству для нас и наших пользователей. Использование модуля Nginx вместо Apache обусловлено нежеланием поддерживать лишнее звено в цепи запуска rails приложений без явной необходимости. Ведь чем проще система, тем удобнее ее поддерживать, а значит и работа будет стабильнее.
А как насчет Unicorn?
>>Мы выбрали для себя связку Nginx + Passenger как самую выгодную по производительности и удобству для нас и наших пользователей.
А теперь у вас связка Apache+Passenger?
Oднотрахники
[…] Рекомендую к прочтению: Выбор сервера приложений для вашего проекта на Rails […]